package com.selune.online.ordering.system.project.customer.service;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.base.Throwables;
import static com.selune.online.ordering.system.common.util.FindUserUtils.getCustomerUserById;
import static com.selune.online.ordering.system.common.util.IdUtils.userGenId;
import com.selune.online.ordering.system.common.util.PasswordSaltUtils;
import com.selune.online.ordering.system.project.api.base.entity.CustomerLogin;
import com.selune.online.ordering.system.project.api.base.entity.CustomerUserInfo;
import com.selune.online.ordering.system.project.api.base.exception.ParamsException;
import com.selune.online.ordering.system.project.api.base.exception.UserException;
import com.selune.online.ordering.system.project.api.base.response.Response;
import com.selune.online.ordering.system.project.api.mapper.CustomerLoginMapper;
import com.selune.online.ordering.system.project.api.mapper.CustomerUserInfoMapper;
import com.selune.online.ordering.system.project.api.pojo.user.customer.dto.CustomerLoginDTO;
import com.selune.online.ordering.system.project.api.pojo.user.customer.dto.CustomerUserDTO;
import com.selune.online.ordering.system.project.api.pojo.user.customer.dto.CustomerUserInfoDTO;
import com.selune.online.ordering.system.project.api.pojo.user.customer.vo.CustomerUserInfoVO;
import com.selune.online.ordering.system.project.api.pojo.user.dto.LoginDTO;
import com.selune.online.ordering.system.project.api.service.customer.ICustomerUserService;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * Created with IntelliJ IDEA.
 *
 * @author xiaoyp
 * @date 2020/3/22
 * <p>
 * Description: 消费者信息管理Service
 */
@Service
@Slf4j
public class CustomerUserServiceImpl implements ICustomerUserService {
	
	@Resource
	private CustomerLoginMapper customerLoginMapper;
	@Resource
	private CustomerUserInfoMapper customerUserInfoMapper;
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Response<Boolean> saveCustomerUser(CustomerUserDTO customerUserDTO) throws UserException {
		if (null == customerUserDTO || StringUtils.isBlank(customerUserDTO.getUserName())
			|| StringUtils.isBlank(customerUserDTO.getUserPassword())
			|| null == customerUserDTO.getUserPhone()) {
			log.error("ACCESS_LOG[]CustomerUserServiceImpl[]saveCustomerUser[]customer user info params is null!");
			return Response.error("user.info.params.is.null");
		}
		Long userId = userGenId();
		CustomerUserInfo customerUserInfo = new CustomerUserInfo();
		CustomerLogin customerLogin = new CustomerLogin();
		
		dtoToEntity(userId, customerUserDTO, customerUserInfo, customerLogin);
		
		CustomerUserInfo customerUserInfo1 = customerUserInfoMapper.selectOne(
			Wrappers.<CustomerUserInfo>lambdaQuery().eq(CustomerUserInfo::getUserPhone,
				customerUserDTO.getUserPhone())
		);
		if (null != customerUserInfo1) {
			return Response.error("手机号已存在");
		}
		
		CustomerUserInfo customerUserInfo2 = customerUserInfoMapper.selectOne(
			Wrappers.<CustomerUserInfo>lambdaQuery().eq(CustomerUserInfo::getUserName,
				customerUserDTO.getUserName())
		);
		if (null != customerUserInfo2) {
			return Response.error("该用户已存在");
		}
		
		/* 加盐 */
		ByteSource salt = ByteSource.Util.bytes(userId.toString());
		String saltPassword = PasswordSaltUtils.salt(customerUserDTO.getUserPassword(), salt);
		
		customerLogin.setPasswordSalt(salt.toHex());
		customerLogin.setUserPassword(saltPassword);
		
		int loginResult = customerLoginMapper.insert(customerLogin);
		int infoResult = customerUserInfoMapper.insert(customerUserInfo);
		if (loginResult == 1 && infoResult == 1) {
			return Response.success("注册成功!", Boolean.TRUE);
		} else {
			return Response.error("注册失败");
		}
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Response<Boolean> updateCustomerUser(Long userId, CustomerUserInfoDTO customerUserInfoDTO) {
		CustomerUserInfo customerUserInfo = getCustomerUserById(customerUserInfoMapper, userId).getData();
		
		customerUserInfoMapper.updateById(customerUserInfo);
		
		log.info("ACCESS_LOG[]CustomerUserServiceImpl[]updateCustomerUser[]update user info success!");
		return Response.success("更新信息成功!", Boolean.TRUE);
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Response<Boolean> updateCustomerLogin(Long userId, CustomerLoginDTO customerLoginDTO) {
		CustomerLogin customerLogin = getCustomerLoginById(userId).getData();
		
		customerLoginMapper.updateById(customerLogin);
		
		log.info("ACCESS_LOG[]CustomerUserServiceImpl[]updateCustomerLogin[]update user info success!");
		return Response.success("更新信息成功!", Boolean.TRUE);
	}
	
	@Override
	public Response<CustomerUserInfoVO> userLogin(LoginDTO loginDTO) {
		String userName = loginDTO.getUserName();
		String userPassword = loginDTO.getUserPassword();
		
		if (StringUtils.isBlank(userName) || StringUtils.isBlank(userPassword)) {
			log.error("ACCESS_LOG[]CustomerUserServiceImpl[]userLogin[]customer name or password is null!");
			throw new ParamsException("user.params.is.null");
		}
		
		CustomerLogin customerLogin = getCustomerLoginByUserName(userName).getData();
		ByteSource salt = ByteSource.Util.bytes(customerLogin.getUserId().toString());
		String password = customerLogin.getUserPassword();
		
		String saltPassword = PasswordSaltUtils.salt(userPassword, salt);
		
		if (!saltPassword.equals(password)) {
			return Response.error("密码错误");
		}
		
		CustomerUserInfo customerUserInfo = customerUserInfoMapper.selectById(customerLogin.getUserId());
		CustomerUserInfoVO customerUserInfoVO = new CustomerUserInfoVO();
		BeanUtils.copyProperties(customerUserInfo, customerUserInfoVO);
		
		log.info("ACCESS_LOG[]CustomerUserServiceImpl[]userLogin[]user login success!");
		return Response.success(customerUserInfoVO);
	}
	
	private void dtoToEntity(Long userId, CustomerUserDTO customerUserDTO, CustomerUserInfo customerUserInfo,
	                         CustomerLogin customerLogin) {
		
		/* customerLogin */
		customerLogin.setId(userId);
		customerLogin.setUserId(userId);
		customerLogin.setUserName(customerUserDTO.getUserName());
		customerLogin.setUserPhone(customerUserDTO.getUserPhone());
		
		/* customerUserInfo */
		customerUserInfo.setId(userId);
		customerUserInfo.setUserId(userId);
		customerUserInfo.setUserName(customerUserDTO.getUserName());
		customerUserInfo.setUserPhone(customerUserDTO.getUserPhone());
		customerUserInfo.setUserEmail(customerUserDTO.getUserEmail());
		customerUserInfo.setUserBirthday(customerUserDTO.getUserBirthday());
	}
	
	private Response<CustomerLogin> getCustomerLoginById(Long userId) {
		if (null == userId) {
			log.error("ACCESS_LOG[]CustomerUserServiceImpl[]getCustomerLoginById[]user_id is null!");
			throw new ParamsException("user.id.is.null");
		}
		CustomerLogin customerLogin;
		
		try {
			customerLogin = customerLoginMapper.selectById(userId);
		} catch (Exception e) {
			log.error("ACCESS_LOG[]CustomerUserServiceImpl[]getCustomerLoginById[]user is not exist! cause:{}",
				Throwables.getStackTraceAsString(e));
			throw new UserException("user.is.not.exist");
		}
		
		if (null == customerLogin) {
			log.error("ACCESS_LOG[]CustomerUserServiceImpl[]getCustomerLoginById[]user is not exist!");
			throw new UserException("user.is.not.exist");
		}
		
		return Response.success(customerLogin);
	}
	
	private Response<CustomerLogin> getCustomerLoginByUserName(String userName) {
		if (StringUtils.isBlank(userName)) {
			log.error("ACCESS_LOG[]CustomerUserServiceImpl[]getCustomerLoginByUserName[]user name is null!");
			throw new ParamsException("user.name.is.null");
		}
		CustomerLogin customerLogin;
		
		try {
			customerLogin = customerLoginMapper.selectOne(
				Wrappers.<CustomerLogin>lambdaUpdate()
					.eq(CustomerLogin::getUserName, userName)
					.eq(CustomerLogin::getIsDelete, Boolean.FALSE)
			);
		} catch (Exception e) {
			log.error("ACCESS_LOG[]CustomerUserServiceImpl[]getCustomerLoginByUserName[]user name is not exist! " +
					"cause:{}",
				Throwables.getStackTraceAsString(e));
			throw new UserException("user.is.not.exist");
		}
		
		return Response.success(customerLogin);
	}
}
